# -*- coding: UTF-8 -*-
"""
@Project ：软件工程实验四（最大积子数组）
@File ：sub_array.py
@Author ：王辰旭
@Date ：2023/5/21
"""
from ast import literal_eval


class SubArray:
    """Class for calculating the sub array"""
    def __init__(self, array=None, operator='*', order='max'):
        """
        Initializer of class SubArray.

        Args:
            array (List[float]: The calculated array.
            operator (str): Type of operator ('+', '*').
            order (str): Max or min sub array ('max', 'min').
        """
        if array is None:
            array = []
        self.array = array
        self.operator = operator
        self.order = order


    def set_array(self, array=None):
        """
        Set the calculated array with a list parameter or input one in the format [1, 2, 3].

        Args:
            array (list): The set array. If this is None, the user will be requested to input an array.

        Returns:
            List[float]: The set array.
        """
        if array is None:
            try:
                array = literal_eval(input("Input the array in the format [1, 2, 3]:"))
            except SyntaxError:
                print("Wrong input format.")
                return None
            except ValueError:
                print("ValueError.")
                return None
            except TypeError:
                print("TypeError.")
                return None
            if isinstance(array, list):
                for index in array:
                    try:
                        assert isinstance(index, (int, float))
                    except AssertionError:
                        print("The array element should be int or float.")
                        return None
            else:
                print("Wrong input format.")
                return None
        self.array = array
        return array


    def mul_max(self):
        """
        Dynamic programming algorithm.

        Returns:
            float: the maximum product of the array.
        """
        max_dp = [0] * len(self.array)
        min_dp = [0] * len(self.array)
        dp_max = [0] * len(self.array)
        max_dp[0] = self.array[0]
        min_dp[0] = self.array[0]
        dp_max[0] = self.array[0]
        for i in range(1, len(self.array)):
            max_dp[i] = max(max_dp[i - 1] * self.array[i], min_dp[i - 1] * self.array[i], self.array[i])
            min_dp[i] = min(max_dp[i - 1] * self.array[i], min_dp[i - 1] * self.array[i], self.array[i])
            dp_max[i] = max(max_dp[i], dp_max[i - 1])
        return dp_max[-1]


    def mul_min(self):
        """
        Dynamic programming algorithm.

        Returns:
            float: the minimum product of the array.
        """
        max_dp = [0] * len(self.array)
        min_dp = [0] * len(self.array)
        dp_min = [0] * len(self.array)
        max_dp[0] = self.array[0]
        min_dp[0] = self.array[0]
        dp_min[0] = self.array[0]
        for i in range(1, len(self.array)):
            max_dp[i] = max(max_dp[i - 1] * self.array[i], min_dp[i - 1] * self.array[i], self.array[i])
            min_dp[i] = min(max_dp[i - 1] * self.array[i], min_dp[i - 1] * self.array[i], self.array[i])
            dp_min[i] = min(min_dp[i], dp_min[i - 1])
        return dp_min[-1]


    def get_result(self):
        """
        Display the result.

        Returns:
            float: the result
        """
        selection = (self.operator, self.order)
        if selection == ("*", "max"):
            return self.mul_max()
        if selection == ("*", "min"):
            return self.mul_min()
        if selection == ("+", "max"):
            return 0  # These can be easily extended
        if selection == ("+", "min"):
            return 0
        print("Bad trap.")
        return -1


def main(array=None, operator='*', order='max'):
    """
    Main function of the program.

    Args:
        array (List[float]): The calculated array. If it is none, the user will be requested to input an array.
        operator (str): Used to initialize SubArray.
        order (str): Used to initialize SubArray.

    Returns:
        float: The result.
    """
    sub_array = SubArray(operator=operator, order=order)
    sub_array.set_array(array)
    result = sub_array.get_result()
    print(f"Operator: {sub_array.operator}")
    print(f"Order: {sub_array.order}")
    print(f"Result: {result}")
    return result


if __name__ == '__main__':
    main()
